package com.bsj.power.pls.web;

import cn.dev33.satoken.annotation.SaIgnore;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bsj.power.common.config.cached.LocationDeviceCached;
import com.bsj.power.common.config.cached.PathCached;
import com.bsj.power.common.config.exception.ApiException;
import com.bsj.power.common.config.global.JsonResult;
import com.bsj.power.common.config.global.JsonResultEnum;
import com.bsj.power.common.config.rocketmq.producer.BaseMqPushUtil;
import com.bsj.power.common.constant.MqTopicAndTagConstants;
import com.bsj.power.common.constant.NumericalConstants;
import com.bsj.power.common.def.dto.DeleteDTO;
import com.bsj.power.common.def.dto.TrackDTO;
import com.bsj.power.common.def.dto.cardReport.BindCardDTO;
import com.bsj.power.common.def.dto.locationDevice.LocationDevice2DDTO;
import com.bsj.power.common.def.dto.locationDevice.LocationDeviceDTO;
import com.bsj.power.common.def.dto.locationDevice.LocationDeviceSearchDTO;
import com.bsj.power.common.def.dto.locationDevice.TagMsgDTO;
import com.bsj.power.common.def.entity.path.Path;
import com.bsj.power.common.def.vo.KeyValueVO;
import com.bsj.power.common.def.vo.PersonAndJobVO;
import com.bsj.power.common.def.vo.VagueVO;
import com.bsj.power.common.def.vo.WebSocketMsgVO;
import com.bsj.power.common.def.vo.pls.AnchorDevice2DVO;
import com.bsj.power.common.def.vo.pls.LocationDeviceVO;
import com.bsj.power.common.def.vo.pls.PosInfoVO;
import com.bsj.power.common.def.vo.pls.excel.AnchorDeviceExcelVO;
import com.bsj.power.common.def.vo.pls.excel.LocationDeviceExcelVO;
import com.bsj.power.common.def.vo.pls.httpVo.HistoryOriginalVO;
import com.bsj.power.common.def.vo.pls.httpVo.HttpTagInfoVO;
import com.bsj.power.common.def.vo.pls.httpVo.HttpTagPosVO;
import com.bsj.power.common.def.vo.tree.TreeStructureVO;
import com.bsj.power.common.mapper.LocationDeviceMapper;
import com.bsj.power.common.mapper.PathMapper;
import com.bsj.power.common.util.DateUtils;
import com.bsj.power.common.util.ExceptionUtil;
import com.bsj.power.pls.file.uwbData.WRFileBaseUntil;
import com.bsj.power.pls.queue.MsgQueue;
import com.bsj.power.pls.service.LocationDeviceService;
import com.bsj.tools.DateUntil;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import com.hikvision.artemis.sdk.constant.Constants;
import com.hikvision.artemis.sdk.constant.ContentType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import redis.clients.bsj.JedisClusterBSJ;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author LiJiaXin
 * @version 1.0.0
 * @description LocationDeviceController
 * @time 2024/4/19 11:04
 */
@Slf4j
@RestController
@RequestMapping("/locationDevice")
//@SaCheckPermission("/pls/locationDevice")
public class LocationDeviceController {

    @Value("${hiKv.host}")
    private String host;

    @Value("${hiKv.appKey}")
    private String appKey;

    @Value("${hiKv.appSecret}")
    private String appSecret;

    @Resource
    private LocationDeviceMapper locationDeviceMapper;

    @Autowired
    private LocationDeviceCached locationDeviceCached;

    @Autowired
    private LocationDeviceService locationDeviceService;

    @Autowired
    private PathCached pathCached;

    @Resource
    private PathMapper pathMapper;

    @Autowired
    private JedisClusterBSJ jedisClusterBSJ;

    @Autowired
    private BaseMqPushUtil baseMqPushUtil;

    @Autowired
    private WRFileBaseUntil wrFileBaseUntil;

    @Autowired
    private MsgQueue msgQueue;

    /**
     * 添加定位设备
     *
     * @param locationDeviceDTO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/4/19 11:35
     */
    @PostMapping("/add")
    public JsonResult add(@Validated @RequestBody LocationDeviceDTO locationDeviceDTO) {
        return locationDeviceService.addLocationDevice(locationDeviceDTO);
    }

    /**
     * 删除定位设备
     *
     * @param deleteDTO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/4/19 11:36
     */
    @PostMapping("/delete")
    public JsonResult delete(@RequestBody DeleteDTO deleteDTO) {
        return locationDeviceService.deleteLocationDevice(deleteDTO);
    }

    /**
     * 修改定位设备
     *
     * @param locationDeviceDTO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/4/19 11:36
     */
    @PostMapping("/update")
    public JsonResult update(@Validated @RequestBody LocationDeviceDTO locationDeviceDTO) {
        return locationDeviceService.updateLocationDevice(locationDeviceDTO);
    }

    /**
     * 获取单个定位设备
     *
     * @param deviceId
     * @return com.bsj.power.common.config.global.JsonResult<com.bsj.power.common.def.vo.pls.LocationDeviceVO>
     * @author ljx
     * @time 2024/4/19 11:36
     */
    @GetMapping("/getById/{deviceId}")
    public JsonResult<LocationDeviceVO> getById(@PathVariable("deviceId") Long deviceId) {
        return JsonResult.success(locationDeviceService.getLocationDeviceById(deviceId));
    }

    /**
     * 定位设备分页
     *
     * @param locationDeviceSearchDTO
     * @return com.bsj.power.common.config.global.JsonResult<java.util.List < com.bsj.power.common.def.vo.pls.LocationDeviceVO>>
     * @author ljx
     * @time 2024/4/19 11:37
     */
    @SaIgnore
    @GetMapping("/page")
    public JsonResult<List<LocationDeviceVO>> page(@Validated LocationDeviceSearchDTO locationDeviceSearchDTO) {
        return locationDeviceService.pageLocationDevice(locationDeviceSearchDTO);
    }

    /**
     * 根据工号获取人员信息与工单信息
     *
     * @param empNo
     * @return com.bsj.power.common.config.global.JsonResult<com.bsj.power.common.def.vo.PersonAndJobVO>
     * @author ljx
     * @time 2024/9/14 19:41
     */
    @GetMapping("/getPersonAndJobInfo/{empNo}")
    public JsonResult<PersonAndJobVO> getPersonAndJobInfo(@PathVariable("empNo") String empNo) {
        return JsonResult.success(locationDeviceService.getPersonAndJobInfo(empNo));
    }

    /**
     * 是否绑定
     *
     * @param bindCardDTO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/5/8 17:09
     */
    @PostMapping("/isBind")
    public JsonResult isBind(@Validated @RequestBody BindCardDTO bindCardDTO) {
        return locationDeviceService.isBind(bindCardDTO, null);
    }


    /**
     * 模糊搜索
     *
     * @param value
     * @param deviceType
     * @return com.bsj.power.common.config.global.JsonResult<java.util.List < com.bsj.power.common.def.vo.KeyValueVO>>
     * @author ljx
     * @time 2024/5/15 16:12
     */
    @GetMapping("/fuzzySearch")
    public JsonResult<List<KeyValueVO>> fuzzySearch(String value, Integer deviceType) {
        return JsonResult.success(locationDeviceService.fuzzySearch(value, deviceType));
    }

    /**
     * 轨迹页面设备或人员模糊搜索
     *
     * @param value
     * @return
     */
    @GetMapping("/fuzzySearch2")
    public JsonResult<List<VagueVO>> fuzzySearch2(String value) {
        return JsonResult.success(locationDeviceService.fuzzySearch2(value));
    }

    /**
     * 轨迹查询
     *
     * @param trackDTO
     * @return
     * @throws ParseException
     */
    @PostMapping("/getTagHistoryData")
    public JsonResult<List<HistoryOriginalVO>> getTagHistoryData(@RequestBody TrackDTO trackDTO) throws ParseException {
        return JsonResult.success(locationDeviceService.getTagHistoryData(trackDTO));
    }

//    /**
//     * getTagHistoryData
//     * 轨迹查询2
//     *
//     * @param trackDTO
//     * @return com.bsj.power.common.config.global.JsonResult<java.util.List < com.bsj.power.common.def.vo.pls.httpVo.HistoryOriginalVO>>
//     * @author ljx
//     * @time 2024/5/25 9:51
//     */
//    @PostMapping("/getTagHistoryData2")
//    public JsonResult<List<HistoryOriginalVO>> getTagHistoryData2(@RequestBody TrackDTO trackDTO) throws ParseException {
//        return JsonResult.success(locationDeviceService.getTagHistoryData2(trackDTO));
//    }


    /**
     * 查询指定工单某一时刻人员的最终位置
     *
     * @param time
     * @param jobId
     * @return
     */
    @GetMapping("/getLastPosition")
    public JsonResult<List<HistoryOriginalVO>> getLastPosition(@RequestParam("time") String time, @RequestParam("jobId") Integer jobId) {
        return locationDeviceService.getLastPosition(time, jobId);
    }


    /**
     * 模拟推送位置数据
     *
     * @return
     */
    @SaIgnore
    @GetMapping("/testPos")
    public JsonResult testPos(String deviceName, String personnelName, String empNo,
                              String startTime, String endTime) throws ParseException, InterruptedException {
        List<Path> paths = pathCached.hgetAllPathInfo();
        long sTime = DateUtils.strToDate(startTime).getTime();
        long eTime = DateUtils.strToDate(endTime).getTime();
        List<HistoryOriginalVO> historyOriginalVOS = new ArrayList<>();
        List<byte[]> listBytes = wrFileBaseUntil.readDataBytes(deviceName, sTime, eTime);
        for (byte[] bytes : listBytes) {
            String data = new String(bytes);
            HttpTagPosVO posData = JSON.parseObject(data, HttpTagPosVO.class);
            HistoryOriginalVO historyOriginalVo = new HistoryOriginalVO();
            //x,y,z
            double[] pos = posData.getPos();
            if (pos.length < 3) {
                continue;
            }
            historyOriginalVo.setDeviceName(deviceName);
            historyOriginalVo.setPos(pos);
            historyOriginalVo.setPersonnelName(personnelName);
            historyOriginalVo.setEmpNo(empNo);
            historyOriginalVo.setTime(DateUntil.dateToDayStr(new Date(posData.getTime())));
            historyOriginalVo.setMapId(posData.getMapId());
            historyOriginalVOS.add(historyOriginalVo);
        }
        if (!CollectionUtils.isEmpty(historyOriginalVOS)) {
            for (HistoryOriginalVO historyOriginalVO : historyOriginalVOS) {
                Thread.sleep(300);
                HttpTagPosVO httpTagPosVO = new HttpTagPosVO(historyOriginalVO);
                httpTagPosVO.setTime(System.currentTimeMillis());
                TagMsgDTO tagMsgDTO = new TagMsgDTO(httpTagPosVO);
                try {
                    msgQueue.push(tagMsgDTO);
                    WebSocketMsgVO webSocketMsgVO = WebSocketMsgVO.builder()
                            .msgType(NumericalConstants.ONE)
                            .obj(httpTagPosVO)
                            .build();
                    baseMqPushUtil.sendTopicBytes(MqTopicAndTagConstants.SYSTEM_WEB_SERVER_CHANGE_TOPIC,
                            MqTopicAndTagConstants.SYSTEM_WEB_PRODUCT_CHANGE_TAG, JSON.toJSONBytes(webSocketMsgVO));
                } catch (Exception e) {
                    log.error("msgQueue写入数据失败:" + ExceptionUtil.getStackStr(e));
                }
            }
        }
        return JsonResult.success();
    }

    /**
     * UWB设备信息导出
     *
     * @param response
     * @param locationDeviceSearchDTO
     * @return void
     * @author ljx
     * @time 2024/5/16 16:28
     */
    @GetMapping("/export")
    public void export(HttpServletResponse response, LocationDeviceSearchDTO locationDeviceSearchDTO) throws IOException {
        List<LocationDeviceExcelVO> locationDeviceExcelVOS = locationDeviceService.getExportData(locationDeviceSearchDTO);
        if (CollectionUtils.isEmpty(locationDeviceExcelVOS)) {
            throw new ApiException(JsonResultEnum.NO_EXPORT_DATA);
        }
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        //编码 防止中文乱码
        String fileName = URLEncoder.encode("UWB设备信息" + DateUtils.dateToStr(DateUtils.TIME_STANDARD_FORMAT2, new Date()), "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        EasyExcelFactory.write(response.getOutputStream(), LocationDeviceExcelVO.class).sheet("UWB设备信息").doWrite(locationDeviceExcelVOS);
    }

    /**
     * 基站设备信息导出
     *
     * @param response
     * @param locationDeviceSearchDTO
     * @return void
     * @author ljx
     * @time 2024/10/24 16:27
     */
    @GetMapping("/exportAnchorDevice")
    public void exportAnchorDevice(HttpServletResponse response, LocationDeviceSearchDTO locationDeviceSearchDTO) throws IOException {
        List<AnchorDeviceExcelVO> anchorDeviceExcelVOS = locationDeviceService.getAnchorExportData(locationDeviceSearchDTO);
        if (CollectionUtils.isEmpty(anchorDeviceExcelVOS)) {
            throw new ApiException(JsonResultEnum.NO_EXPORT_DATA);
        }
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        //编码 防止中文乱码
        String fileName = URLEncoder.encode("基站设备信息" + DateUtils.dateToStr(DateUtils.TIME_STANDARD_FORMAT2, new Date()), "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        EasyExcelFactory.write(response.getOutputStream(), AnchorDeviceExcelVO.class).sheet("基站设备信息").doWrite(anchorDeviceExcelVOS);
    }

    /**
     * 设置模拟数据
     *
     * @param httpTagInfoVO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/5/28 19:44
     */
    @PostMapping("/setSimulatedData")
    public JsonResult setSimulatedData(@Validated @RequestBody HttpTagInfoVO httpTagInfoVO) {
        String value = jedisClusterBSJ.get("LOCATION:DEVICE:SIMULATED:DATA");
        List<HttpTagInfoVO> httpTagInfoVOS = new LinkedList<>();
        if (StringUtils.isBlank(value)) {
            httpTagInfoVOS.add(httpTagInfoVO);
        } else {
            JSONArray jsonArray = JSONObject.parseArray(value);
            httpTagInfoVOS = jsonArray.toJavaList(HttpTagInfoVO.class);
            //去重覆盖
            httpTagInfoVOS.add(httpTagInfoVO);
            httpTagInfoVOS = httpTagInfoVOS.stream().collect(Collectors.toMap(HttpTagInfoVO::getSn, Function.identity(), (v1, v2) -> v2)).values().stream().collect(Collectors.toList());
        }
        jedisClusterBSJ.set("LOCATION:DEVICE:SIMULATED:DATA", JSONObject.toJSONString(httpTagInfoVOS));
        log.info("设备状态缓存信息{}", httpTagInfoVOS);
        return JsonResult.success();
    }

    /**
     * 获取定位信息
     *
     * @param deviceName
     * @return com.bsj.power.common.config.global.JsonResult<com.bsj.power.common.def.vo.pls.PosInfoVO>
     * @author ljx
     * @time 2024/6/5 12:03
     */
    @GetMapping("/getPosInfo")
    public JsonResult<PosInfoVO> getPosInfo(String deviceName) {
        return JsonResult.success(locationDeviceService.getPosInfo(deviceName));
    }

    /**
     * 人脸识别
     *
     * @return
     */
    @SaIgnore
    @GetMapping("/facialRecognition")
    public JsonResult facialRecognition(String personNo) {
        ArtemisConfig.host = host;
        ArtemisConfig.appKey = appKey;
        ArtemisConfig.appSecret = appSecret;
        log.info("海康平台颁发参数：host：{}  appKey：{}  appSecret：{}", host, appKey, appSecret);

        final String ARTEMIS_PATH = "/artemis";
        final String url = "/api/resource/v1/person/condition/personInfo";
        Map<String, String> path = Map.of("https://", ARTEMIS_PATH + url);
        //超时5秒
        Constants.DEFAULT_TIMEOUT = 5000;

        String[] array = {personNo};
        JSONObject jsonBody = new JSONObject();
        //根据人员唯一字段获取人员详细信息请求参数
        jsonBody.put("paramName", "personId");
        jsonBody.put("paramValue", array);
        String body = jsonBody.toString();
        log.info("接口入参：{}", body);
        String result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, ContentType.CONTENT_TYPE_JSON);
        log.info("根据人员唯一字段获取人员详细信息返回结果{}", result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            Integer code = jsonObject.getInteger("code");
            if (code != null && code.equals(NumericalConstants.ZERO)) {
                return JsonResult.success(result);
            } else {
                log.info("人脸识别失败，请求参数{}", body);
                return JsonResult.fail();
            }
        } else {
            log.info("人脸识别失败，请求参数{}", body);
            return JsonResult.fail();
        }
    }

    /**
     * 基站设备树结构
     *
     * @return com.bsj.power.common.config.global.JsonResult<java.util.List < com.bsj.power.common.def.vo.SceneTreeVO>>
     * @author ljx
     * @time 2024/10/7 11:37
     */
    @GetMapping("/tree")
    public JsonResult<List<TreeStructureVO>> tree() {
        return JsonResult.success(locationDeviceService.getTreeStructureVO());
    }

    /**
     * 清除基站二维信息
     *
     * @param deviceNames
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/10/29 14:12
     */
    @GetMapping("/cleanAnchor2DInfo")
    public JsonResult cleanAnchor2DInfo(String[] deviceNames) {
        return locationDeviceService.cleanAnchor2DInfo(deviceNames);
    }

    /**
     * 设置基站二维信息
     *
     * @param locationDevice2DDTOS
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/10/29 10:20
     */
    @PostMapping("/setAnchor2DInfo")
    public JsonResult setAnchor2DInfo(@RequestBody List<LocationDevice2DDTO> locationDevice2DDTOS) {
        return locationDeviceService.setAnchor2DInfo(locationDevice2DDTOS);
    }

    /**
     * 根据栋数和楼层查询基站设备二维信息
     *
     * @param building
     * @param floor
     * @return com.bsj.power.common.config.global.JsonResult<com.bsj.power.common.def.vo.pls.AnchorDevice2DVO>
     * @author ljx
     * @time 2024/10/29 11:11
     */
    @GetMapping("/listAnchor2DInfo")
    public JsonResult<AnchorDevice2DVO> listAnchor2DInfo(Integer building, Integer floor) {
        return JsonResult.success(locationDeviceService.listDevice2DInfo(building, floor));
    }

    /**
     * 导入基站设备信息
     *
     * @param file
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/10/29 16:07
     */
    @PostMapping("/importLocationDeviceInfo")
    public JsonResult importLocationDeviceInfo(MultipartFile file) throws IOException {
        return locationDeviceService.setNikeName(file);
    }

    /**
     * 标签设备是否锁定
     *
     * @param deviceName 设备号
     * @param isLockIn   是否锁定 1是 2否
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/12/6 10:49
     */
    @GetMapping("/isLockIn")
    public JsonResult isLockIn(String deviceName, Integer isLockIn) {
        return locationDeviceService.isLockIn(deviceName, isLockIn);
    }

}
